package com.yic.module.wms.service.erpproducein;

import cn.hutool.core.util.ObjectUtil;
import com.yic.module.base.api.factory.FactoryApi;
import com.yic.module.base.api.factory.dto.FactoryRespDTO;
import com.yic.module.base.api.item.ItemApi;
import com.yic.module.base.api.item.dto.ItemRespDTO;
import com.yic.module.external.api.erp.ErpMoRecetptApi;
import com.yic.module.external.api.erp.dto.ErpMoRecetptCreateReqDTO;
import com.yic.module.external.api.erp.dto.ErpMoRecetptCreateRespDTO;
import com.yic.module.external.api.erp.dto.ErpMoRecetptInfoCreateReqDTO;
import com.yic.module.mes.api.plan.PlanApi;
import com.yic.module.mes.api.plan.dto.PlanRespDTO;
import com.yic.module.mes.api.report.ReportApi;
import com.yic.module.mes.api.report.dto.ReportRespDTO;
import com.yic.module.mes.api.report.dto.ReportUpdateReqDTO;
import com.yic.module.system.enums.common.ApproveEnum;
import com.yic.module.system.enums.dict.SystemAppTypeEnum;
import com.yic.module.system.enums.dict.SystemBooleanEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.*;
import com.yic.module.wms.controller.admin.erpproducein.vo.*;
import com.yic.module.wms.dal.dataobject.erpproducein.ErpProduceInDO;
import com.yic.framework.common.pojo.PageResult;

import com.yic.module.wms.convert.erpproducein.ErpProduceInConvert;
import com.yic.module.wms.dal.mysql.erpproducein.ErpProduceInMapper;

import static com.yic.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yic.module.wms.enums.ErrorCodeConstants.*;

/**
 * erp生产入库 Service 实现类
 *
 * @author 系统管理员
 */
@Service
@Validated
@Slf4j
public class ErpProduceInServiceImpl implements ErpProduceInService {

    @Resource
    private ErpProduceInMapper erpProduceInMapper;
    @Resource
    private PlanApi planApi;
    @Resource
    private ErpMoRecetptApi moRecetptApi;
    @Resource
    private FactoryApi factoryApi;
    @Resource
    private ReportApi reportApi;
    @Resource
    private ItemApi itemApi;
    @Resource
    private TransactionTemplate transactionTemplate;

    @Override
    public Long createErpProduceIn(ErpProduceInCreateReqVO createReqVO) {
        PlanRespDTO planRespDTO = validateCreateOrUpdate(null, createReqVO.getCode(), createReqVO.getPlanId(), createReqVO.getAcceptedQty(), createReqVO.getReportIds());
        // 获取工厂信息
        FactoryRespDTO factory = factoryApi.getFactory(createReqVO.getFactoryId());
        if (ObjectUtil.isEmpty(factory)) {
            throw exception(ERP_PRODUCE_IN_FACTORY_NOT_EXISTS);
        }
        // 获取产品信息
        ItemRespDTO item = itemApi.getItem(planRespDTO.getItemId());
        if (ObjectUtil.isEmpty(item)) {
            throw exception(ERP_PRODUCE_IN_ITEM_NOT_EXISTS);
        }
        // 插入
        ErpProduceInDO erpProduceIn = ErpProduceInConvert.INSTANCE.convert(createReqVO);
        // 调用erp接口抛转生产入库单据
        List<ErpMoRecetptInfoCreateReqDTO> list = new ArrayList<>();
        ErpMoRecetptInfoCreateReqDTO infoCreateReqDTO = new ErpMoRecetptInfoCreateReqDTO();
        infoCreateReqDTO.setPlanCode(planRespDTO.getCode());
        infoCreateReqDTO.setProductType("1");
        infoCreateReqDTO.setItemCode(item.getCode());
        infoCreateReqDTO.setAcceptedQty(createReqVO.getAcceptedQty());
        infoCreateReqDTO.setScrapQty(createReqVO.getScrapQty());
        infoCreateReqDTO.setDestroyedQty(createReqVO.getDestroyedQty());
        infoCreateReqDTO.setWarehouseCode(planRespDTO.getErpWarehouseCode());
        infoCreateReqDTO.setBinCode(createReqVO.getErpBinCode());
        infoCreateReqDTO.setItemLotCode(planRespDTO.getErpItemLotCode());
        infoCreateReqDTO.setRemark("");
        list.add(infoCreateReqDTO);

        ErpMoRecetptCreateReqDTO createReqDTO = new ErpMoRecetptCreateReqDTO();
        createReqDTO.setFactoryCode(factory.getCode());
        createReqDTO.setDocCode(createReqVO.getErpDocCode());
        createReqDTO.setDocDate(createReqVO.getErpDocDate());
        createReqDTO.setCenterCode(createReqVO.getErpCenterCode());
        createReqDTO.setCode(createReqVO.getCode());
        createReqDTO.setRemark("");
        createReqDTO.setUserCode("");
        createReqDTO.setList(list);

        ErpMoRecetptCreateRespDTO respDTO = moRecetptApi.saveMoRecetpt(createReqDTO);
        // 处理本系统数据
        erpProduceIn.setWorkshopId(planRespDTO.getWorkshopId());
        erpProduceIn.setErpDocNo(respDTO.getErpCode());
        erpProduceIn.setBatchNo(planRespDTO.getBatchNo());
        erpProduceIn.setRequest(respDTO.getRequest());
        erpProduceIn.setResponse(respDTO.getResponse());
        erpProduceIn.setRespCode(respDTO.getCode());
        erpProduceIn.setDescription(respDTO.getDescription());
        erpProduceIn.setRemark(planRespDTO.getRemark());
        erpProduceIn.setStatus(ApproveEnum.WAIT.getApprove());
        erpProduceIn.setItemId(planRespDTO.getItemId());
        if ("0".equals(respDTO.getCode()) && "Y".equals(respDTO.getDocStatus())) {
            erpProduceIn.setStatus(ApproveEnum.PASS.getApprove());
        }
        // 入库
        transactionTemplate.execute(status -> {
            try {
                erpProduceInMapper.insert(erpProduceIn);
                // 更新报工标识
                List<ReportUpdateReqDTO> reports = new ArrayList<>(createReqVO.getReportIds().size());
                createReqVO.getReportIds().forEach(id -> {
                    ReportUpdateReqDTO reqDTO = new ReportUpdateReqDTO();
                    reqDTO.setId(id);
                    reqDTO.setErpProduceInId(erpProduceIn.getId());
                    reports.add(reqDTO);
                });
                reportApi.batchUpdateReport(reports);
                return Boolean.TRUE;
            }catch (Exception e) {
                e.printStackTrace();
                status.setRollbackOnly();
                if ("0".equals(respDTO.getCode())) {
                    moRecetptApi.cancelMoRecetpt(erpProduceIn.getErpDocNo()); //撤销erp入库单据
                }
                return Boolean.FALSE;
            }
        });
        // 返回
        return erpProduceIn.getId();
    }

    @Override
    public void updateErpProduceIn(ErpProduceInUpdateReqVO updateReqVO) {
        // 校验存在
        validateErpProduceInExists(updateReqVO.getId());
        // 更新
        ErpProduceInDO updateObj = ErpProduceInConvert.INSTANCE.convert(updateReqVO);
        erpProduceInMapper.updateById(updateObj);
    }

    @Override
    public void deleteErpProduceIn(Long id) {
        // 校验存在
        validateErpProduceInExists(id);
        // 删除
        erpProduceInMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelErpProduceIn(Long id) {
        // 删除入库
        ErpProduceInDO erpProduceInDO = validateErpProduceInExists(id);
        erpProduceInMapper.deleteById(id);
        // 更新报工
        reportApi.updateReportByErpInId(id);
        moRecetptApi.cancelMoRecetpt(erpProduceInDO.getErpDocNo());
    }

    private PlanRespDTO validateCreateOrUpdate(Long id, String code, Long planId, BigDecimal acceptedQty, Collection<Long> reportIds) {
        validateCodeExists(id, code);
        return validateAcceptedQty(planId, acceptedQty, reportIds);
    }

    private void validateCodeExists(Long id, String code) {
        ErpProduceInDO erpProduceInDO = erpProduceInMapper.selectByCode(code);
        if (ObjectUtil.isEmpty(erpProduceInDO)) {
            return;
        }
        if (id == null) {
            throw exception(ERP_PRODUCE_IN_CODE_EXISTS);
        }
        if (!erpProduceInDO.getId().equals(id)) {
            throw exception(ERP_PRODUCE_IN_CODE_EXISTS);
        }
    }

    private PlanRespDTO validateAcceptedQty(Long planId, BigDecimal acceptedQty, Collection<Long> reportIds) {
        //查询生产计划已入库数量
        List<ErpProduceInDO> erpProduceInDOS = erpProduceInMapper.selectByPlanId(planId, SystemBooleanEnum.YES.getSystemBoolean());
        BigDecimal accepted = erpProduceInDOS.stream().map(ErpProduceInDO::getAcceptedQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        //查询生产计划
        PlanRespDTO plan = planApi.getPlan(planId);
        //计算待入库数量
        BigDecimal noAccept = plan.getPlanAmount().subtract(accepted);
        if (acceptedQty.compareTo(noAccept) > 0) {
            throw exception(ERP_PRODUCE_IN_GREATER_PLAN_AMOUNT, plan.getCode(), accepted, noAccept);
        }
        //查询报工数据并核对
        List<ReportRespDTO> reportList = reportApi.getReportList(reportIds);
        BigDecimal reportAmount = reportList.stream().map(ReportRespDTO::getReportAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (reportAmount.compareTo(acceptedQty) != 0) {
            throw exception(ERP_PRODUCE_IN_NOT_EQUAL_PRODUCE, plan.getCode(), acceptedQty, reportAmount);
        }
        return plan;
    }

    private ErpProduceInDO validateErpProduceInExists(Long id) {
        ErpProduceInDO erpProduceInDO = erpProduceInMapper.selectById(id);
        if (erpProduceInDO == null) {
            throw exception(ERP_PRODUCE_IN_NOT_EXISTS);
        }
        return erpProduceInDO;
    }

    @Override
    public ErpProduceInDO getErpProduceIn(Long id) {
        return erpProduceInMapper.selectById(id);
    }

    @Override
    public List<ErpProduceInDO> getErpProduceInList(Collection<Long> ids) {
        return erpProduceInMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ErpProduceInDO> getErpProduceInPage(ErpProduceInPageReqVO pageReqVO) {
        return erpProduceInMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ErpProduceInDO> getErpProduceInList(ErpProduceInExportReqVO exportReqVO) {
        return erpProduceInMapper.selectList(exportReqVO);
    }

}
